package janino;

import j2me.io.File;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.codehaus.janino.Compiler;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import org.codehaus.janino.util.resource.PathResourceFinder;

public class JaninoMIDlet extends MIDlet implements CommandListener, Runnable {

    private final Form console;
    private final TextField campoEntrada;
    private final TextField campoSaida;
    private final TextField campoClassPath;
    private final TextField campoBootClassPath;
    private final TextBox campoArquivo;
    private final Command comandoSair;
    private final Command comandoCompilar;
    private final Command comandoSalvar;
    private final Command comandoAbrir;
    private final Command okCommand;
    private final Display display;
    private String opcao = "";
    private RecordStore rs;

    public JaninoMIDlet() {
        console = new Form("Janino");

        campoEntrada = new TextField("-soucepath:", null, 256, TextField.ANY);
        campoClassPath = new TextField("-classpath: ", null, 256, TextField.ANY);
        campoBootClassPath = new TextField("-bootclasspath", null, 256, TextField.ANY);
        campoSaida = new TextField("-d:", null, 256, TextField.ANY);
        campoArquivo = new TextBox("Arquivo", null, 256, TextField.ANY);

        console.append(campoEntrada);
        console.append(campoClassPath);
        console.append(campoBootClassPath);
        console.append(campoSaida);

        okCommand = new Command("Ok", Command.OK, 0);
        campoArquivo.addCommand(okCommand);
        campoArquivo.setCommandListener(this);

        comandoSair = new Command("Sair", Command.EXIT, 0);
        comandoCompilar = new Command("Compilar", Command.OK, 1);
        comandoSalvar = new Command("Salvar", Command.SCREEN, 2);
        comandoAbrir = new Command("Carregar", Command.SCREEN, 3);

        console.addCommand(comandoSair);
        console.addCommand(comandoCompilar);
        console.addCommand(comandoSalvar);
        console.addCommand(comandoAbrir);

        console.setCommandListener(this);

        display = Display.getDisplay(this);

        try {
            rs = RecordStore.openRecordStore("janino", true);
            if (rs.getNumRecords() < 1) {
                rs.addRecord(new byte[0], 0, 0);
            }
        } catch (RecordStoreException ex) {
            ex.printStackTrace();
        }

        carregaArquivo();
    }

    void carregaArquivo() {
        try {
            byte[] record = rs.getRecord(1);
            if (record == null) {
                return;
            }
            DataInputStream in = new DataInputStream(new ByteArrayInputStream(record));
            String arquivo = in.readUTF();
            campoArquivo.setString(arquivo);
            carregaDados();
        } catch (RecordStoreException ex) {
        } catch (IOException ex) {
        }
    }

    void salvaArquivo() {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        try {
            dos.writeUTF(campoArquivo.getString());
            byte[] record = baos.toByteArray();
            rs.setRecord(1, record, 0, record.length);
        } catch (IOException ex) {
        } catch (RecordStoreException ex) {
        }

    }

    public void startApp() {
        display.setCurrent(console);
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }

    public void commandAction(Command c, Displayable d) {
        if (d == console) {
            if (c == comandoSair) {
                destroyApp(true);
                notifyDestroyed();
            } else if (c == comandoCompilar) {
                new Thread(this).start();
            } else if (c == comandoSalvar) {
                opcao = "Salvar";
                display.setCurrent(campoArquivo);
            } else if (c == comandoAbrir) {
                opcao = "Abrir";
                display.setCurrent(campoArquivo);
            }
        } else if (d == campoArquivo) {
            if (c == okCommand) {
                if (opcao.equals("Abrir")) {
                    carregaDados();
                    salvaArquivo();
                }

                if (opcao.equals("Salvar")) {
                    salvaDados();
                    salvaArquivo();
                }

                display.setCurrent(console);
            }
        }
    }

    private void salvaDados() {
        new Thread(new Runnable() {

            public void run() {
                try {
                    FileConnection conn = (FileConnection) Connector.open("file:///" + campoArquivo.getString());

                    if (!conn.exists()) {
                        conn.create();
                    }

                    DataOutputStream out = conn.openDataOutputStream();
                    out.writeUTF(campoEntrada.getString());
                    out.writeUTF(campoClassPath.getString());
                    out.writeUTF(campoBootClassPath.getString());
                    out.writeUTF(campoSaida.getString());
                    out.close();

                    conn.close();
                } catch (IOException ex) {
                }

            }
        }).start();
    }

    private void carregaDados() {
        new Thread(new Runnable() {

            public void run() {
                try {
                    FileConnection conn = (FileConnection) Connector.open("file:///" + campoArquivo.getString());

                    DataInputStream in = conn.openDataInputStream();
                    campoEntrada.setString(in.readUTF());
                    campoClassPath.setString(in.readUTF());
                    campoBootClassPath.setString(in.readUTF());
                    campoSaida.setString(in.readUTF());
                    in.close();

                    conn.close();
                } catch (IOException ex) {
                }

            }
        }).start();
    }

    public void run() {
        Vector constroiArgs = new Vector();

        constroiArgs.addElement("-sourcepath");
        constroiArgs.addElement(campoEntrada.getString());

        constroiArgs.addElement("-classpath");
        constroiArgs.addElement(campoClassPath.getString());

        constroiArgs.addElement("-bootclasspath");
        constroiArgs.addElement(campoBootClassPath.getString());

        constroiArgs.addElement("-d");
        constroiArgs.addElement(campoSaida.getString());

        try {
            File[] files = PathResourceFinder.parsePath(campoEntrada.getString());
            File file;
            for (int i = 0; i < files.length; i++) {
                file = files[i];
                listSourceFiles(file.getURL(), constroiArgs);
            }
        } catch (IOException ex) {
            console.append("Problema ao listar arquivos de código fonte\n");
            console.append(ex.toString() + "\n");
            ex.printStackTrace();
        }

        String[] args = new String[constroiArgs.size()];
        constroiArgs.copyInto(args);

        try {
            console.append("Compilando...\n");
            Compiler.consoleOut = new PrintStream(new FormOutputStream(console));
            Compiler.main(args);
        } catch (IOException ex) {
            // console.append("Problema ao compilar\n");
            console.append(ex.toString() + "\n");
        } catch (Error er) {
            console.append(er.toString() + "\n");
            er.printStackTrace();
        }

        console.append("Concluído!\n");
    }

    void listSourceFiles(String url, Vector vector) throws IOException {
        //System.out.println(url);
        FileConnection fc = (FileConnection) Connector.open(url);
        Enumeration e = fc.list();
        String filename;
        while (e.hasMoreElements()) {
            filename = (String) e.nextElement();
            //  System.out.println(filename);
            if (filename.endsWith("/")) {
                listSourceFiles(fc.getURL() + filename, vector);
            } else if (filename.endsWith(".java")) {
                vector.addElement(fc.getURL() + filename);
            }
        }
    }

    String verifyDirectory(String dir) {
        if (!dir.endsWith("/")) {
            return dir + "/";
        } else {
            return dir;
        }
    }
}
